#ifndef RAY_TRACE_PRO_MATERIAL_H
#define RAY_TRACE_PRO_MATERIAL_H

#include "Shader.h"
#include "Basic/GxLibBasic.h"
#include "RayTraceSystem.h"

namespace RayTracePro
{
	using namespace GxLibBasic;

	class RayDifferential;

	class GIMaterial
	{
	public:
		//bool Enabled;
		bool Reflect;
		bool Refract;
		bool Lambert;
		ShadingNodeParameter ReflectionRate;
		ShadingNodeParameter Diffuse;
		GIMaterial()
		{
			Reflect = Refract = Lambert = false;
		}
		void EvaluateGI(GxLibMath::Vec4 & result, DifferentialGeometry * dgeom, const Ray * ray, const RayDifferential * rayDiff, Scene * scene, int depth);
		void EstimateGI(GxLibMath::Vec4 & result, DifferentialGeometry * dgeom, const Ray * ray, const RayDifferential * rayDiff, Scene * scene, int depth);
	};

	class Material
	{
		friend class RayTraceSystemImpl;
	private:
		Material()
		{
			Shader = 0;
		}
	public:
		~Material()
		{
			if (Shader)
				Shader->Free();
		}
		GIMaterial GI;
		ShadingNode * Shader;
		inline void Shade(GxLibMath::Vec4 * result, RayTraceSystem * system, DifferentialGeometry * dgeom, const Ray * ray, const RayDifferential * rayDiff, Scene * scene, int depth)
		{
			GxLibMath::Vec4 rs;
			result->SetZero();
			
			if (Shader)
			{
				Shader->Shade(result, dgeom, ray, rayDiff, scene, depth);
			}
			
			if (system->EnableGI)
			{
				rs.SetZero();
				if (system->EnableFinalGather)
					GI.EvaluateGI(rs, dgeom, ray, rayDiff, scene, depth);
				else
					GI.EstimateGI(rs, dgeom, ray, rayDiff, scene, depth);
				Vec4 diffuse;
				GI.Diffuse.Get(&diffuse, dgeom, ray, rayDiff, scene, depth);
				rs *= diffuse;
				(*result) += rs;
			}
			
		}
	};
}

#endif